package com.configtools.service;

import com.configtools.model.ExcelColumn;
import com.configtools.model.ExcelSheet;
import com.configtools.model.JavaField;
import com.configtools.model.JavaClass;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Excel解析服务
 * 负责解析Excel文件，提取配置信息
 * 
 * @author ConfigTools Team
 * @version 1.0.0
 */
@Slf4j
public class ExcelParserService {

    /**
     * 解析Excel文件，提取配置信息
     * 
     * @param excelFile Excel文件
     * @return Excel配置信息列表
     * @throws Exception 解析异常
     */
    public List<ExcelSheet> parseExcelFile(File excelFile) throws Exception {
        log.info("开始解析Excel文件: {}", excelFile.getName());
        
        if (!excelFile.exists()) {
            throw new IllegalArgumentException("Excel文件不存在: " + excelFile.getAbsolutePath());
        }
        
        if (!isExcelFile(excelFile)) {
            throw new IllegalArgumentException("不是有效的Excel文件: " + excelFile.getName());
        }
        
        try (FileInputStream fis = new FileInputStream(excelFile);
             Workbook workbook = createWorkbook(fis, excelFile.getName())) {
            
            List<ExcelSheet> sheets = new ArrayList<>();
            
            // 遍历所有工作表
            for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
                Sheet sheet = workbook.getSheetAt(i);
                String sheetName = sheet.getSheetName();
                
                // 跳过空工作表
                if (sheet.getPhysicalNumberOfRows() < 4) {
                    log.warn("工作表 {} 行数不足4行，跳过", sheetName);
                    continue;
                }
                
                try {
                    ExcelSheet excelSheet = parseSheet(sheet, excelFile.getName());
                    if (excelSheet != null) {
                        sheets.add(excelSheet);
                        log.info("成功解析工作表: {}", sheetName);
                    }
                } catch (Exception e) {
                    log.error("解析工作表 {} 失败: {}", sheetName, e.getMessage());
                    // 继续解析其他工作表
                }
            }
            
            log.info("Excel文件解析完成，共解析 {} 个工作表", sheets.size());
            return sheets;
            
        } catch (Exception e) {
            log.error("解析Excel文件失败: {}", e.getMessage(), e);
            throw new Exception("解析Excel文件失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 解析单个工作表
     * 
     * @param sheet 工作表
     * @param excelFileName Excel文件名
     * @return 工作表配置信息
     */
    private ExcelSheet parseSheet(Sheet sheet, String excelFileName) {
        String sheetName = sheet.getSheetName();
        
        // 读取前4行
        Row commentRow = sheet.getRow(0);  // 第1行：中文注释
        Row typeRow = sheet.getRow(1);     // 第2行：Java类型
        Row fieldRow = sheet.getRow(2);    // 第3行：字段名
        Row markRow = sheet.getRow(3);     // 第4行：标记行
        
        if (commentRow == null || typeRow == null || fieldRow == null || markRow == null) {
            log.warn("工作表 {} 行数据不完整，跳过", sheetName);
            return null;
        }
        
        List<ExcelColumn> columns = new ArrayList<>();
        
        // 遍历列，提取列信息
        for (int colIndex = 0; colIndex < Math.min(commentRow.getLastCellNum(), 100); colIndex++) {
            try {
                ExcelColumn column = parseColumn(commentRow, typeRow, fieldRow, markRow, colIndex);
                if (column != null) {
                    columns.add(column);
                }
            } catch (Exception e) {
                log.warn("解析第 {} 列失败: {}", colIndex + 1, e.getMessage());
                // 继续解析其他列
            }
        }
        
        // 验证必要的列
        if (!validateRequiredColumns(columns)) {
            log.warn("工作表 {} 缺少必要的列（sid），跳过", sheetName);
            return null;
        }
        
        // 创建Java类信息
        JavaClass javaClass = createJavaClass(sheetName, columns, excelFileName);
        
        return ExcelSheet.builder()
                .sheetName(sheetName)
                .excelFileName(excelFileName)
                .columns(columns)
                .javaClass(javaClass)
                .build();
    }
    
    /**
     * 解析单个列
     * 
     * @param commentRow 注释行
     * @param typeRow 类型行
     * @param fieldRow 字段行
     * @param markRow 标记行
     * @param colIndex 列索引
     * @return 列信息
     */
    private ExcelColumn parseColumn(Row commentRow, Row typeRow, Row fieldRow, Row markRow, int colIndex) {
        Cell commentCell = commentRow.getCell(colIndex);
        Cell typeCell = typeRow.getCell(colIndex);
        Cell fieldCell = fieldRow.getCell(colIndex);
        Cell markCell = markRow.getCell(colIndex);
        
        // 获取列值
        String comment = getCellValue(commentCell);
        String type = getCellValue(typeCell);
        String fieldName = getCellValue(fieldCell);
        String mark = getCellValue(markCell);
        
        // 跳过空列
        if (isEmpty(comment) && isEmpty(type) && isEmpty(fieldName)) {
            return null;
        }
        
        // 验证字段名
        if (isEmpty(fieldName)) {
            log.warn("第 {} 列缺少字段名，跳过", colIndex + 1);
            return null;
        }
        
        // 验证类型
        if (isEmpty(type)) {
            log.warn("第 {} 列缺少类型信息，跳过", colIndex + 1);
            return null;
        }
        
        // 检查是否为客户端标记
        boolean isClientOnly = "client".equalsIgnoreCase(mark);
        
        // 创建Java字段信息
        JavaField javaField = createJavaField(fieldName, type, comment, isClientOnly);
        
        return ExcelColumn.builder()
                .columnIndex(colIndex)
                .comment(comment)
                .type(type)
                .fieldName(fieldName)
                .mark(mark)
                .isClientOnly(isClientOnly)
                .javaField(javaField)
                .build();
    }
    
    /**
     * 创建Java字段信息
     * 
     * @param fieldName 字段名
     * @param type 字段类型
     * @param comment 注释
     * @param isClientOnly 是否仅客户端
     * @return Java字段信息
     */
    private JavaField createJavaField(String fieldName, String type, String comment, boolean isClientOnly) {
        // 转换Java类型
        String javaType = convertToJavaType(type);
        
        // 生成getter方法名
        String getterName = generateGetterName(fieldName, javaType);
        
        return JavaField.builder()
                .name(fieldName)
                .type(javaType)
                .comment(comment)
                .isClientOnly(isClientOnly)
                .getterName(getterName)
                .build();
    }
    
    /**
     * 创建Java类信息
     * 
     * @param sheetName 工作表名
     * @param columns 列信息
     * @param excelFileName Excel文件名
     * @return Java类信息
     */
    private JavaClass createJavaClass(String sheetName, List<ExcelColumn> columns, String excelFileName) {
        // 生成类名（驼峰命名）
        String className = generateClassName(sheetName);
        
        // 过滤非客户端字段
        List<JavaField> fields = columns.stream()
                .filter(col -> !col.isClientOnly())
                .map(ExcelColumn::getJavaField)
                .collect(Collectors.toList());
        
        return JavaClass.builder()
                .className(className)
                .sheetName(sheetName)
                .excelFileName(excelFileName)
                .fields(fields)
                .build();
    }
    
    /**
     * 转换Excel类型为Java类型
     * 
     * @param excelType Excel类型
     * @return Java类型
     */
    private String convertToJavaType(String excelType) {
        if (excelType == null) {
            return "String";
        }
        
        String type = excelType.trim().toLowerCase();
        
        switch (type) {
            case "int":
            case "integer":
                return "int";
            case "long":
                return "long";
            case "boolean":
            case "bool":
                return "boolean";
            case "double":
                return "double";
            case "float":
                return "float";
            case "short":
                return "short";
            case "byte":
                return "byte";
            case "string":
            case "str":
            default:
                return "String";
        }
    }
    
    /**
     * 生成getter方法名
     * 
     * @param fieldName 字段名
     * @param javaType Java类型
     * @return getter方法名
     */
    private String generateGetterName(String fieldName, String javaType) {
        if ("boolean".equals(javaType)) {
            // boolean类型使用is前缀
            return "is" + capitalize(fieldName);
        } else {
            // 其他类型使用get前缀
            return "get" + capitalize(fieldName);
        }
    }
    
    /**
     * 生成类名（驼峰命名）
     * 
     * @param sheetName 工作表名
     * @return 类名
     */
    private String generateClassName(String sheetName) {
        if (isEmpty(sheetName)) {
            return "DefaultCfg";
        }
        
        // 移除特殊字符，转换为驼峰命名
        String[] parts = sheetName.split("[^a-zA-Z0-9]+");
        StringBuilder className = new StringBuilder();
        
        for (String part : parts) {
            if (!isEmpty(part)) {
                className.append(capitalize(part.toLowerCase()));
            }
        }
        String classNameStr = className.toString();
        if (classNameStr.endsWith("Cfg") || classNameStr.endsWith("cfg")) {
            classNameStr = classNameStr.substring(0, classNameStr.length() - 3);
        }
        
        return classNameStr + "Cfg";
    }
    
    /**
     * 首字母大写
     * 
     * @param str 字符串
     * @return 首字母大写的字符串
     */
    private String capitalize(String str) {
        if (isEmpty(str)) {
            return str;
        }
        return str.substring(0, 1).toUpperCase() + str.substring(1);
    }
    
    /**
     * 验证必要的列
     * 
     * @param columns 列信息
     * @return 是否包含必要的列
     */
    private boolean validateRequiredColumns(List<ExcelColumn> columns) {
        return columns.stream()
                .anyMatch(col -> "sid".equals(col.getFieldName()) && "int".equalsIgnoreCase(col.getType()));
    }
    
    /**
     * 获取单元格值
     * 
     * @param cell 单元格
     * @return 单元格值
     */
    private String getCellValue(Cell cell) {
        if (cell == null) {
            return "";
        }
        
        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    return cell.getDateCellValue().toString();
                } else {
                    return String.valueOf((long) cell.getNumericCellValue());
                }
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                try {
                    return String.valueOf(cell.getNumericCellValue());
                } catch (Exception e) {
                    return cell.getStringCellValue();
                }
            default:
                return "";
        }
    }
    
    /**
     * 检查字符串是否为空
     * 
     * @param str 字符串
     * @return 是否为空
     */
    private boolean isEmpty(String str) {
        return str == null || str.trim().isEmpty();
    }
    
    /**
     * 检查是否为Excel文件
     * 
     * @param file 文件
     * @return 是否为Excel文件
     */
    private boolean isExcelFile(File file) {
        String fileName = file.getName().toLowerCase();
        return fileName.endsWith(".xlsx") || fileName.endsWith(".xls");
    }
    
    /**
     * 创建Workbook
     * 
     * @param fis 文件输入流
     * @param fileName 文件名
     * @return Workbook
     * @throws IOException IO异常
     */
    private Workbook createWorkbook(FileInputStream fis, String fileName) throws IOException {
        if (fileName.toLowerCase().endsWith(".xlsx")) {
            return new XSSFWorkbook(fis);
        } else {
            return new HSSFWorkbook(fis);
        }
    }
}
